classdef NanoObj < handle
    %   NanoObj includes information about an atomistics structure.
    %   Detailes explanation goes here
    
    properties  
        
      Periodicity = [];
    
     
    end
    properties (GetAccess = public, SetAccess = private)
        Atoms = []; 
        AtomProperties = [];
        AtomListProperties = [];
    end
    
    properties (GetAccess = private, SetAccess = public)
        AtomsDatabase = []; 
        SortPlot = [];

    end
    
    properties (GetAccess = private, SetAccess = private)
       index = [];
    end
    
    methods 
        
        function n_atoms = natoms(obj)
            n_atoms = length(obj.Atoms);
        end
        
        function obj = NanoObj(varargin)
            
            obj.Atoms = containers.Map('KeyType','uint64', 'ValueType','any');
            obj.AtomsDatabase = containers.Map('KeyType','char', 'ValueType','any');
            obj.AtomProperties = containers.Map('KeyType','uint64','ValueType','any');
            obj.AtomListProperties = containers.Map('KeyType','char','ValueType','uint64');
            
            obj.index = 0;
            if nargin == 2 %Atom is specified
               obj.add_atom(varargin{1},varargin{2});
            end
            if (nargin == 1)  
               if isa(varargin{1},'NanoObj')
                   
                  obj = NanoObj;
                  obji = varargin{1};
                  indexes = obji.Atoms.keys;
                  
                  for k = 1:numel(indexes)
                      Atom = obji.get_atom(indexes{k});
                      obj.add_atom(Atom);                          
                  end
                 
               else
                  obj.read(varargin{1});
               end
            end
        end
    
        %function obj2 = copy(obj)
        %          obj2 = NanoObj;
        %          indexes = obj.Atoms.Keys;
        %          for k = 1:numel(indexes)
        %              Atom = obj.get_atom(indexes{k});
        %              obj.add_atoms(Atom.Position,Atom.Kind);                          
        %          end         
        %end
        
        %---------------------------Interfaces
        function indexes = select(obj,varargin)           
            indexes = eval(strcat('obj.select_',varargin{1},'(varargin{2})'));
        end
        
        
        %Get a given property for all atoms
        function [property] = get_property(obj,varargin)
            
             kind = varargin{1};
        
             indexes = obj.Atoms.keys;
             natoms = numel(indexes);
             
             property_index = obj.AtomListProperties(char(kind));
             
             for k = 1:natoms
               properties = obj.AtomProperties(indexes{k});
               property(k) = properties(property_index);
             end
           
        end
        
        %Get positions for all atoms
        function [positions] = get_positions(obj,varargin)
            
             if (nargin == 1) 
              indexes = obj.Atoms.keys;
             else
              indexes = varargin{1};   
             end
             
             natoms = numel(indexes);
             positions = zeros(natoms,3);
             
             for k = 1:numel(indexes)
              positions(k,:) = obj.Atoms(indexes(k)).Position;   
             end
           
        end
        %function transform(obj,varargin)
        %    eval(strcat('Transform.',varargin{1},'(obj,varargin{2:end})'));
        %end
        
        function import(obj,varargin)
            filename = varargin{1};
            filetype = filename(end-2:end);
            eval(strcat('import_',filetype,'(obj,varargin{:})'));
        end
        
        function plot(obj,varargin)
            
            %ImportDataBase
            DB=importdata('DataBase.dat2');
            for k=1:size(DB.data,1)
                properties = DB.data(k,:);
                obj.AtomsDatabase(char(DB.textdata(k,2))) = properties;
            end
            
            if (nargin == 1)
              filename = 'structure.vmd'; %%Default = vmd
            else
              filename = varargin{1};
            end
            
              filetype = filename(end-2:end);
              eval(strcat('plot_',filetype,'(obj,varargin)'));
        end
        
        %function write(obj,varargin)
        %    filename = varargin{1};
        %    filetype = filename(end-2:end);
        %    eval(strcat('write_',filetype,'(obj,varargin)'));
        %end
           
        %function plot(obj,varargin)   
            
         %   if nargin == 1
         %       visualizer = 'vmd'; %%Default = vmd
         %   else
         %       visualizer = char(varargin{1});
         %   end
            
         %   eval(strcat('obj.plot_',visualizer,'(obj,varargin{2:end})'));
        %end
        %------------------------------------
        
        %compute_box
        function[box] = compute_box(obj) 
          box = zeros(3,2);
          pos = zeros(obj.natoms,3);
          indexes = obj.Atoms.keys;
          for ka=1:numel(indexes)
            pos(ka,:)=obj.Atoms(indexes{ka}).Position;
          end

          box(1,1) = min(pos(:,1));
          box(1,2) = max(pos(:,1));
          box(2,1) = min(pos(:,2));
          box(2,2) = max(pos(:,2));
          box(3,1) = min(pos(:,3));
          box(3,2) = max(pos(:,3));
        end
        
        %Add some special feature on the database
        function add_atom_properties(obj,varargin)
            obj.AtomsDatabase(varargin{1}) = varargin{2};
        end
        
        %add_atom
        function output = add_atom(obj,varargin)
            obj.index = obj.index + 1;
            if (nargin == 2)
               obj.Atoms(obj.index) = varargin{1};
            else
               obj.Atoms(obj.index) = struct('Position',varargin{1},'Kind',varargin{2});     
            end
            output =  obj.index; 
        end
        
        function rm_atom(obj,index)
            obj.Atoms.remove(index);
        end
        
        function atom = get_atom(obj,index)
            atom = obj.Atoms(index);
        end
        
        function set_element(obj,index,varargin)
            
             if (isKey(obj.Atoms,{index}))
                 Atom = struct('Position',obj.Atoms(index).Position,'Kind',varargin{1});
                 obj.Atoms(index) = Atom;
             else  
                 error(strcat('No Atoms with index: ',index)); 
             end
          
        end
        
        
         function set_position(obj,index,varargin)
             if (isKey(obj.Atoms,{index}))
               Atom = struct('Position',varargin{1},'Kind',obj.Atoms(index).Kind);
                obj.Atoms(index) = Atom;  
             else  
                 error(strcat('No Atoms with index: ',index)); 
             end
          
         end
         
         function output = duplicate_atom(obj,index,varargin)
             
             if (isKey(obj.Atoms,{index}))
               Atom = obj.Atoms(index);
               output = obj.add_atom(Atom);
               if (nargin == 3)
                  obj.set_element(output,varargin{1});
               end
               if (nargin == 4)
                  obj.set_element(output,varargin{1});
                  obj.translate(output,varargin{2});
               end      
             else  
                 error(strcat('No Atoms with index: ',index)); 
             end
          
         end
       
        
         
        function[output] = set_atom(obj,index,varargin)
            if (isKey(obj.Atoms,{index}))
               if (nargin == 3)
                   obj.Atoms(index) = varargin{1};
               else
                   Atom = struct('Position',varargin{1},'Kind',varargin{2});
                   obj.Atoms(index) = Atom;
               end
            else
               error(strcat('No Atoms with index: ',index)); 
            end
               
        end
        
        replicate(obj,vec);
        translate(obj,varargin);
        output = neighbor(obj,varargin); 
        rotate(obj,direction,theta);
        %rotate_periodicity(obj,direction,theta);
        
        
        % Plus operator
        function obj = plus(obj1,obj2)
            obj = obj1;
            indexes = obj2.Atoms.keys;
            for k = 1:numel(indexes)
              Atom = obj2.Atoms(indexes{k});  
              obj.add_atom(Atom); 
            end   
            A1  = obj1.Periodicity;
            A2  = obj2.Periodicity;
            obj.Periodicity = A1 + A2;
        end
       
        
    end
    
end

